//SPDX-FileCopyrightText: Copyright 2022-2024 深圳市同心圆网络有限公司
//SPDX-License-Identifier: GPL-3.0-only

package project_bulletin_api_serv

import (
	"context"
	"time"

	"atomgit.com/openlinksaas/api-server/api_common"
	"atomgit.com/openlinksaas/api-server/dao"
	"atomgit.com/openlinksaas/api-server/dao/bulletin_dao"
	"atomgit.com/openlinksaas/api-server/dao/project_dao"
	"atomgit.com/openlinksaas/api-server/dao/user_dao"
	"atomgit.com/openlinksaas/api-server/utils"
	"atomgit.com/openlinksaas/proto-gen-go.git/notices/notices_project"
	"atomgit.com/openlinksaas/proto-gen-go.git/project_bulletin_api"
	"atomgit.com/openlinksaas/proto-gen-go.git/project_recycle_api"
	"github.com/google/uuid"
	"go.mongodb.org/mongo-driver/mongo"
)

type ProjectBulletinApiImpl struct {
	project_bulletin_api.UnimplementedProjectBulletinApiServer
}

func (apiImpl *ProjectBulletinApiImpl) Create(ctx context.Context, req *project_bulletin_api.CreateRequest) (*project_bulletin_api.CreateResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_bulletin_api.CreateResponse{
			Code:   project_bulletin_api.CreateResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	//检查权限
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_bulletin_api.CreateResponse{
			Code:   project_bulletin_api.CreateResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_bulletin_api.CreateResponse{
			Code:   project_bulletin_api.CreateResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}
	if projectItem.Closed {
		return &project_bulletin_api.CreateResponse{
			Code:   project_bulletin_api.CreateResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}
	//只有管理员可以操作
	if !(sessionItem.UserId == projectItem.OwnerUserId || roleItem.BasicInfo.Admin) {
		return &project_bulletin_api.CreateResponse{
			Code:   project_bulletin_api.CreateResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	bulletInId := uuid.NewString()
	nowTime := time.Now().UnixNano() / 1e6
	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = bulletin_dao.BulletinInfoDao.Insert(sessCtx, &bulletin_dao.BulletinInfoDbItem{
			BulletinId:   bulletInId,
			ProjectId:    req.ProjectId,
			Title:        req.Title,
			CreateUserId: sessionItem.UserId,
			CreateTime:   nowTime,
			UpdateUserId: sessionItem.UserId,
			UpdateTime:   nowTime,
		})
		if err != nil {
			return nil, err
		}
		err = dao.MsgDataDao.Insert(sessCtx, &dao.MsgDataDBItem{
			MsgId:        bulletInId,
			Content:      req.Content,
			CreateUserId: sessionItem.UserId,
			CreateTime:   nowTime,
			HasChanged:   false,
		})
		if err != nil {
			return nil, err
		}
		memberItemList, err := project_dao.MemberInfoDao.ListMember(sessCtx, req.ProjectId)
		if err != nil {
			return nil, err
		}
		for _, memberItem := range memberItemList {
			err = bulletin_dao.UnReadInfoDao.Insert(sessCtx, &bulletin_dao.UnReadInfoDbItem{
				ProjectId:    req.ProjectId,
				MemberUserId: memberItem.MemberUserId,
				BulletinId:   bulletInId,
				TimeStamp:    nowTime,
			})
			if err != nil {
				return nil, err
			}
		}
		return &project_bulletin_api.CreateResponse{
			Code:       project_bulletin_api.CreateResponse_CODE_OK,
			BulletinId: bulletInId,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	//发送通知
	go api_common.SendNoticeToProjectScope(context.Background(), req.ProjectId, &notices_project.CreateBulletinNotice{
		ProjectId:    req.ProjectId,
		BulletinId:   bulletInId,
		CreateUserId: sessionItem.UserId,
	})
	return ret.(*project_bulletin_api.CreateResponse), nil
}

func (apiImpl *ProjectBulletinApiImpl) Update(ctx context.Context, req *project_bulletin_api.UpdateRequest) (*project_bulletin_api.UpdateResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_bulletin_api.UpdateResponse{
			Code:   project_bulletin_api.UpdateResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	//检查权限
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_bulletin_api.UpdateResponse{
			Code:   project_bulletin_api.UpdateResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_bulletin_api.UpdateResponse{
			Code:   project_bulletin_api.UpdateResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}
	if projectItem.Closed {
		return &project_bulletin_api.UpdateResponse{
			Code:   project_bulletin_api.UpdateResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}
	//只有管理员可以操作
	if !(sessionItem.UserId == projectItem.OwnerUserId || roleItem.BasicInfo.Admin) {
		return &project_bulletin_api.UpdateResponse{
			Code:   project_bulletin_api.UpdateResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}
	exist, err := bulletin_dao.BulletinInfoDao.Exist(ctx, req.BulletinId, req.ProjectId)
	if err != nil {
		return nil, err
	}
	if !exist {
		return &project_bulletin_api.UpdateResponse{
			Code:   project_bulletin_api.UpdateResponse_CODE_NO_BULLETIN,
			ErrMsg: "公告不存在",
		}, nil
	}

	nowTime := time.Now().UnixNano() / 1e6
	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = bulletin_dao.BulletinInfoDao.UpdateTitle(sessCtx, req.BulletinId, req.ProjectId, req.Title, sessionItem.UserId, nowTime)
		if err != nil {
			return nil, err
		}
		err = dao.MsgDataDao.Update(sessCtx, req.BulletinId, req.Content)
		if err != nil {
			return nil, err
		}
		return &project_bulletin_api.UpdateResponse{
			Code: project_bulletin_api.UpdateResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	//发送通知
	go api_common.SendNoticeToProjectScope(context.Background(), req.ProjectId, &notices_project.UpdateBulletinNotice{
		ProjectId:  req.ProjectId,
		BulletinId: req.BulletinId,
	})
	return ret.(*project_bulletin_api.UpdateResponse), nil
}

func (apiImpl *ProjectBulletinApiImpl) Remove(ctx context.Context, req *project_bulletin_api.RemoveRequest) (*project_bulletin_api.RemoveResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_bulletin_api.RemoveResponse{
			Code:   project_bulletin_api.RemoveResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	//检查权限
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_bulletin_api.RemoveResponse{
			Code:   project_bulletin_api.RemoveResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_bulletin_api.RemoveResponse{
			Code:   project_bulletin_api.RemoveResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}
	if projectItem.Closed {
		return &project_bulletin_api.RemoveResponse{
			Code:   project_bulletin_api.RemoveResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}
	//只有管理员可以操作
	if !(sessionItem.UserId == projectItem.OwnerUserId || roleItem.BasicInfo.Admin) {
		return &project_bulletin_api.RemoveResponse{
			Code:   project_bulletin_api.RemoveResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}
	bulletinItem, err := bulletin_dao.BulletinInfoDao.Get(ctx, req.BulletinId, req.ProjectId)
	if err != nil {
		return &project_bulletin_api.RemoveResponse{
			Code:   project_bulletin_api.RemoveResponse_CODE_NO_BULLETIN,
			ErrMsg: "公告不存在",
		}, nil
	}

	nowTime := time.Now().UnixNano() / 1e6

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = bulletin_dao.BulletinInfoDao.Remove(sessCtx, req.BulletinId, req.ProjectId)
		if err != nil {
			return nil, err
		}
		//写入回收站
		err = bulletin_dao.BulletinRecycleDao.Insert(sessCtx, bulletinItem)
		if err != nil {
			return nil, err
		}
		err = project_dao.RecycleDao.Insert(sessCtx, &project_dao.RecycleItemInfoDbItem{
			RecycleItemId:   req.BulletinId,
			ProjectId:       req.ProjectId,
			RecycleItemType: uint32(project_recycle_api.RECYCLE_ITEM_TYPE_RECYCLE_ITEM_BULLETIN),
			RemoveUserId:    sessionItem.UserId,
			RemoveTime:      nowTime,
		})
		if err != nil {
			return nil, err
		}
		err = bulletin_dao.UnReadInfoDao.RemoveByBulletin(sessCtx, req.ProjectId, req.BulletinId)
		if err != nil {
			return nil, err
		}
		return &project_bulletin_api.RemoveResponse{
			Code: project_bulletin_api.RemoveResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	//发送通知
	go api_common.SendNoticeToProjectScope(context.Background(), req.ProjectId, &notices_project.RemoveBulletinNotice{
		ProjectId:  req.ProjectId,
		BulletinId: req.BulletinId,
	})
	return ret.(*project_bulletin_api.RemoveResponse), nil
}

func (apiImpl *ProjectBulletinApiImpl) ListKey(ctx context.Context, req *project_bulletin_api.ListKeyRequest) (*project_bulletin_api.ListKeyResponse, error) {
	emptyList := []*project_bulletin_api.BulletinInfoKey{}

	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_bulletin_api.ListKeyResponse{
			Code:    project_bulletin_api.ListKeyResponse_CODE_WRONG_SESSION,
			ErrMsg:  "会话不存在",
			KeyList: emptyList,
		}, nil
	}
	//检查权限
	_, _, _, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_bulletin_api.ListKeyResponse{
			Code:    project_bulletin_api.ListKeyResponse_CODE_NO_PROJECT,
			ErrMsg:  "项目不存在",
			KeyList: emptyList,
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_bulletin_api.ListKeyResponse{
			Code:    project_bulletin_api.ListKeyResponse_CODE_NO_PERMISSION,
			ErrMsg:  "没有权限",
			KeyList: emptyList,
		}, nil
	} else if err != nil {
		return nil, err
	}
	var count uint32
	var bulletinItemList []*bulletin_dao.BulletinInfoDbItem
	if req.ListUnRead {
		count, err = bulletin_dao.UnReadInfoDao.Count(ctx, req.ProjectId, sessionItem.UserId)
		if err != nil {
			return nil, err
		}
		unReadItemList, err := bulletin_dao.UnReadInfoDao.List(ctx, req.ProjectId, sessionItem.UserId, int64(req.Offset), int64(req.Limit))
		if err != nil {
			return nil, err
		}
		bulletinIdList := []string{}
		for _, unReadItem := range unReadItemList {
			bulletinIdList = append(bulletinIdList, unReadItem.BulletinId)
		}
		bulletinItemList, err = bulletin_dao.BulletinInfoDao.ListById(ctx, req.ProjectId, bulletinIdList)
		if err != nil {
			return nil, err
		}
	} else {
		count, err = bulletin_dao.BulletinInfoDao.Count(ctx, req.ProjectId)
		if err != nil {
			return nil, err
		}
		bulletinItemList, err = bulletin_dao.BulletinInfoDao.List(ctx, req.ProjectId, int64(req.Offset), int64(req.Limit))
		if err != nil {
			return nil, err
		}
	}
	//获取所有未读公告
	bulletinIdList := []string{}
	for _, bulletinItem := range bulletinItemList {
		bulletinIdList = append(bulletinIdList, bulletinItem.BulletinId)
	}
	unReadBulletinIdList, err := bulletin_dao.UnReadInfoDao.DistinctById(ctx, req.ProjectId, sessionItem.UserId, bulletinIdList)
	if err != nil {
		return nil, err
	}
	unReadBulletinIdMap := map[string]bool{}
	for _, unReadBulletinId := range unReadBulletinIdList {
		unReadBulletinIdMap[unReadBulletinId] = true
	}
	//补充用户信息
	userIdList := []string{}
	for _, bulletinItem := range bulletinItemList {
		userIdList = append(userIdList, bulletinItem.CreateUserId)
		userIdList = append(userIdList, bulletinItem.UpdateUserId)
	}
	userItemList, err := user_dao.UserInfoDao.ListById(ctx, userIdList)
	if err != nil {
		return nil, err
	}
	userItemMap := map[string]*user_dao.UserInfoDbItem{}
	for _, userItem := range userItemList {
		userItemMap[userItem.UserId] = userItem
	}
	//生成结果
	infoList := []*project_bulletin_api.BulletinInfoKey{}
	for _, bulletinItem := range bulletinItemList {
		info := bulletinItem.ToBulletinInfoKey()
		createUser, ok := userItemMap[bulletinItem.CreateUserId]
		if ok {
			info.CreateDisplayName = createUser.BasicInfo.DisplayName
			info.CreateLogoUri = createUser.BasicInfo.LogoUri
		}
		updateUser, ok := userItemMap[bulletinItem.UpdateUserId]
		if ok {
			info.UpdateDisplayName = updateUser.BasicInfo.DisplayName
			info.UpdateLogoUri = updateUser.BasicInfo.LogoUri
		}
		info.MyUnRead = unReadBulletinIdMap[bulletinItem.BulletinId]
		infoList = append(infoList, info)
	}
	return &project_bulletin_api.ListKeyResponse{
		Code:       project_bulletin_api.ListKeyResponse_CODE_OK,
		TotalCount: count,
		KeyList:    infoList,
	}, nil
}

func (apiImpl *ProjectBulletinApiImpl) Get(ctx context.Context, req *project_bulletin_api.GetRequest) (*project_bulletin_api.GetResponse, error) {
	emptyInfo := &project_bulletin_api.BulletinInfoKey{}
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_bulletin_api.GetResponse{
			Code:    project_bulletin_api.GetResponse_CODE_WRONG_SESSION,
			ErrMsg:  "会话不存在",
			KeyInfo: emptyInfo,
		}, nil
	}
	//检查权限
	_, _, _, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_bulletin_api.GetResponse{
			Code:    project_bulletin_api.GetResponse_CODE_NO_PROJECT,
			ErrMsg:  "项目不存在",
			KeyInfo: emptyInfo,
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_bulletin_api.GetResponse{
			Code:    project_bulletin_api.GetResponse_CODE_NO_PERMISSION,
			ErrMsg:  "没有权限",
			KeyInfo: emptyInfo,
		}, nil
	} else if err != nil {
		return nil, err
	}
	bulletinItem, err := bulletin_dao.BulletinInfoDao.Get(ctx, req.BulletinId, req.ProjectId)
	if err != nil {
		return &project_bulletin_api.GetResponse{
			Code:    project_bulletin_api.GetResponse_CODE_NO_BULLETIN,
			ErrMsg:  "公告不存在",
			KeyInfo: emptyInfo,
		}, nil
	}
	unReadExist, err := bulletin_dao.UnReadInfoDao.Exist(ctx, req.ProjectId, sessionItem.UserId, req.BulletinId)
	if err != nil {
		return nil, err
	}
	//获取内容
	contentItem, err := dao.MsgDataDao.Get(ctx, req.BulletinId)
	if err != nil {
		return &project_bulletin_api.GetResponse{
			Code:    project_bulletin_api.GetResponse_CODE_NO_BULLETIN,
			ErrMsg:  "公告不存在",
			KeyInfo: emptyInfo,
		}, nil
	}
	//补全用户信息
	userItemList, err := user_dao.UserInfoDao.ListById(ctx, []string{bulletinItem.CreateUserId, bulletinItem.UpdateUserId})
	if err != nil {
		return nil, err
	}
	userItemMap := map[string]*user_dao.UserInfoDbItem{}
	for _, userItem := range userItemList {
		userItemMap[userItem.UserId] = userItem
	}
	//生成结果
	info := bulletinItem.ToBulletinInfoKey()
	createUser, ok := userItemMap[bulletinItem.CreateUserId]
	if ok {
		info.CreateDisplayName = createUser.BasicInfo.DisplayName
		info.CreateLogoUri = createUser.BasicInfo.LogoUri
	}
	updateUser, ok := userItemMap[bulletinItem.UpdateUserId]
	if ok {
		info.UpdateDisplayName = updateUser.BasicInfo.DisplayName
		info.UpdateLogoUri = updateUser.BasicInfo.LogoUri
	}
	info.MyUnRead = unReadExist
	return &project_bulletin_api.GetResponse{
		Code:    project_bulletin_api.GetResponse_CODE_OK,
		KeyInfo: info,
		Content: contentItem.Content,
	}, nil
}

func (apiImpl *ProjectBulletinApiImpl) MarkRead(ctx context.Context, req *project_bulletin_api.MarkReadRequest) (*project_bulletin_api.MarkReadResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_bulletin_api.MarkReadResponse{
			Code:   project_bulletin_api.MarkReadResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	//检查权限
	_, _, _, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_bulletin_api.MarkReadResponse{
			Code:   project_bulletin_api.MarkReadResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_bulletin_api.MarkReadResponse{
			Code:   project_bulletin_api.MarkReadResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}
	exist, err := bulletin_dao.BulletinInfoDao.Exist(ctx, req.BulletinId, req.ProjectId)
	if err != nil {
		return nil, err
	}
	if !exist {
		return &project_bulletin_api.MarkReadResponse{
			Code:   project_bulletin_api.MarkReadResponse_CODE_NO_BULLETIN,
			ErrMsg: "公告不存在",
		}, nil
	}

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = bulletin_dao.UnReadInfoDao.Remove(sessCtx, req.ProjectId, sessionItem.UserId, req.BulletinId)
		if err != nil {
			return nil, err
		}
		return &project_bulletin_api.MarkReadResponse{
			Code: project_bulletin_api.MarkReadResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	return ret.(*project_bulletin_api.MarkReadResponse), nil
}
